from django.utils import timezone
from django_redis import get_redis_connection
from rest_framework import serializers
from django.db import transaction
from decimal import Decimal

from goods.models import SKU
from .models import OrderInfo, OrderGoods


class SaveOrderSerializer(serializers.ModelSerializer):
    """
    保存订单序列化器
    """
    class Meta:
        model = OrderInfo
        fields = ['order_id', 'address', 'pay_method']
        read_only_fields = ('order_id',)
        extra_kwargs = {
            'address': {
                'write_only': True,
                'required': True,
            },
            'pay_method': {
                'write_only': True,
                'required': True
            }
        }

    def create(self, validated_data):
        """
        重写create方法，实现保存订单的数据库保存操作
        需要对数据库四张表进行操作：goods/sku/orderinfo/ordergoods
        goods中修改sales字段（SPU的销量）
        sku表中的sales字段（SKU销量）和stock字段（SKU库存）
        orderinfo增加订单信息
        ordergoods中增加订单中的商品的信息
        """
        user = self.context['request'].user
        # 生成order_id
        order_id = timezone.now().strftime('%Y%m%d%H%M%S') + ('%09d' % user.id)

        address = validated_data.get('address')
        pay_method = validated_data.get('pay_method')

        with transaction.atomic():
            # 创建一个保存点
            save_id = transaction.savepoint()

            try:
                # 保存订单信息
                new_order = OrderInfo.objects.create(
                            order_id=order_id,
                            user=user,
                            address=address,
                            total_count=0,
                            total_amount=Decimal('0'),
                            freight=Decimal('10.00'),
                            pay_method=pay_method,
                            status=OrderInfo.ORDER_STATUS_ENUM['UNSEND'] if pay_method == OrderInfo.PAY_METHODS_ENUM['CASH'] else OrderInfo.ORDER_STATUS_ENUM['UNPAID']
                        )

                redis_conn = get_redis_connection('cart')
                redis_cart = redis_conn.hgetall('cart_%s' % user.id)
                redis_selected = redis_conn.smembers('selected_%s' % user.id)

                cart_dict = {}
                for sku_id in redis_selected:
                    cart_dict[int(sku_id)] = int(redis_cart[sku_id])

                sku_ids = cart_dict.keys()
                # skus = SKU.objects.filter(id__in=cart_dict.keys())
                for sku_id in sku_ids:
                    while True:
                        sku = SKU.objects.get(id=sku_id)

                        origin_stock = sku.stock  # 原始库存
                        origin_sales = sku.sales  # 原始销量

                        # 判断库存
                        sku_count = cart_dict[sku.id]
                        if sku_count > sku.stock:
                            transaction.savepoint_rollback(save_id)  # 回滚
                            raise serializers.ValidationError('库存不足')

                        # 模拟延迟
                        # import time
                        # time.sleep(5)

                        # sku.stock -= sku_count  # 减SKU库存
                        # sku.sales += sku_count  # 加SKU销量
                        # sku.save()

                        # 更新库存
                        new_stock = origin_stock - sku_count
                        new_sales = origin_sales + sku_count

                        # 乐观锁更新库存
                        result = SKU.objects.filter(id=sku_id, stock=origin_stock).update(stock=new_stock, sales=new_sales)
                        # 如果下单失败，但是库存足够的情况下，继续下单，直到下单成功或者库存确实不足就停止
                        if result == 0:
                            continue

                        sku.goods.sales += sku_count  # 加SPU销量
                        sku.goods.save()

                        # 保存订单商品信息
                        OrderGoods.objects.create(
                            order=new_order,
                            sku=sku,
                            count=sku_count,
                            price=sku.price
                        )

                        # 保存商品订单中的总价和数量
                        new_order.total_count += sku_count
                        new_order.total_amount += (sku_count * sku.price)

                        break

                # 总价加入邮费
                new_order.total_amount += new_order.freight
                # 保存
                new_order.save()

            except serializers.ValidationError:
                raise
            except Exception:
                transaction.savepoint_rollback(save_id)  # 回滚
                raise

        # 清除购物⻋车中已结算的商品
        pl = redis_conn.pipeline()
        pl.hdel('cart_%s' % user.id, *redis_selected)
        pl.srem('selected_%s' % user.id, *redis_selected)
        pl.execute()

        return new_order


class CartSKUSerializer(serializers.ModelSerializer):
    """
    订单页面商品序列化器
    """
    count = serializers.IntegerField(label='商品数量')

    class Meta:
        model = SKU
        fields = ['id', 'name', 'default_image_url', 'price', 'count']


class OrderSettlementSerializer(serializers.Serializer):
    """
    订单页面结算详情序列化器
    """
    # DecimalField字段为精确浮点数，max_digits指定浮点数最大位数，decimal_places指定浮点数小数点后面有几位数
    freight = serializers.DecimalField(label='运费', max_digits=10, decimal_places=2)
    skus = CartSKUSerializer(many=True)